﻿var Bicycle = new Interface("Bicycle", ['assemble', 'wash', 'ride', 'repair', 'getPrice']);
var BicycleShop = function () { };
BicycleShop.prototype = {
    sellBicycle: function (model) {
        var bicycle = this.createBicycle(model);

        // Decorator
        console.log(bicycle.getPrice());
        bicycle = new HeadlightDecorator(bicycle);
        console.log(bicycle);
        console.log(bicycle.getPrice());
        bicycle = new TaillightDecorator(bicycle);


        return bicycle;
    },
    createBicycle: function (model) {
        throw new Error("Unsupported operation on an abstract class.");
    }
};

var SilverBicycleShop = function () { };
extend(SilverBicycleShop, BicycleShop);
SilverBicycleShop.prototype.createBicycle = function (model) {
    var bicycle;

    switch (model) {
        case "The Speedster":
            bicycle = new Speedster();
            break;
        case "The Lowrider":
            bicycle = new Lowrider();
            break;
        case "The Comfort Cruiser":
        default:
            bicycle = new ComfortCruiser();
    }

    Interface.ensureImplements(bicycle, Bicycle);
    return bicycle;
}

var Speedster = function () {
    this.No = this.getGuid();
};

Speedster.prototype = {
    getGuid: function () {
        var guid = "";
        for (var i = 1; i <= 32; i++) {
            var n = Math.floor(Math.random() * 16.0).toString(16);
            guid += n;
            if ((i == 8) || (i == 12) || (i == 16) || (i == 20))
                guid += "-";
        }
        return "Speedster" + guid;
    },
    assemble: function () {
        return (this.No + " is assembling");
    },
    wash: function () {
        return (this.No + " is washing");
    },
    ride: function () {
        return (this.No + " is riding");
    },
    repair: function () {
        return (this.No + " is repairing");
    },
    getPrice: function () {
        return 399.00;
    }

}

var BicycleDecorator = function (bicycle) {
    Interface.ensureImplements(bicycle, Bicycle);
    this.bicycle = bicycle;
};
BicycleDecorator.prototype = {
    assemble: function () {
        return this.bicycle.assemble();
    },
    wash: function () {
        return this.bicycle.wash();
    },
    ride: function () {
        return this.bicycle.ride();
    },
    repair: function () {
        return this.bicylce.repair();
    },
    getPrice: function () {
        return this.bicycle.getPrice();
    }
};

var HeadlightDecorator = function (bicycle) {
    this.constructor(bicycle);
};
extend(HeadlightDecorator, BicycleDecorator);
HeadlightDecorator.prototype.assemble = function () {
    return this.bicycle.assemble() + ' Attach headlight to handlebars.';
};
HeadlightDecorator.prototype.getPrice = function () {
    return this.bicycle.getPrice() + 15.00;
};

var TaillightDecorator = function (bicycle) {
    this.constructor(bicycle);
};
extend(TaillightDecorator, BicycleDecorator);
TaillightDecorator.prototype.assemble = function () {
    return this.bicycle.assemble() + ' Attach taillight to the seat post.';
};
TaillightDecorator.prototype.getPrice = function () {
    return this.bicycle.getPrice() + 9.00;
};

